Skip to content

Electron 生产环境代码加固方案

🎯 开篇核心考点提示

面试官常问:

  1. Electron 应用如何防止源码被反编译?
  2. asar 打包是否足够安全?如何增强?
  3. 如何在运行时保护敏感数据和核心逻辑?
  4. 企业级 Electron 应用的完整安全策略是什么?

核心原则:

⚠️ Electron 无法做到绝对安全,只能提高破解成本

本质:Node.js + Chromium → 前端代码天然是明文


📊 一、加固策略总览(四层防护)

层级防护措施难度提升实现复杂度
源码层JS 混淆、字符串加密⭐⭐⭐
构建层asar 打包、二次加密⭐⭐⭐⭐
运行时内存解密、防调试、完整性校验⭐⭐⭐⭐⭐
分发层代码签名、HTTPS 更新⭐⭐⭐

完整防护流程图

mermaid
graph TD
    A[开发阶段] --> B[JS 代码混淆]
    B --> C[敏感字符串 AES 加密]
    C --> D[构建打包]
    D --> E[asar 打包]
    E --> F[asar 二次加密]
    F --> G[计算 Hash 校验值]
    G --> H[运行时加载]
    H --> I[内存解密 asar]
    I --> J[防调试检测]
    J --> K[Hash 完整性校验]
    K --> L{校验通过?}
    L -->|是| M[正常运行]
    L -->|否| N[强制退出]
    M --> O[代码签名验证]
    O --> P[HTTPS 自动更新]

🔐 二、源码层加固(基础必做)

2.1 JS 代码混淆

工具对比

工具混淆强度性能影响适用场景推荐指数
javascript-obfuscator⭐⭐⭐⭐⭐中等生产环境⭐⭐⭐⭐⭐
terser⭐⭐极低仅压缩⭐⭐⭐
uglify-js⭐⭐已淘汰

安装与配置

bash
npm install javascript-obfuscator --save-dev

混淆脚本示例

js
// scripts/obfuscate.js
const JavaScriptObfuscator = require('javascript-obfuscator');
const fs = require('fs');
const path = require('path');

function obfuscateFile(inputPath, outputPath) {
  const code = fs.readFileSync(inputPath, 'utf-8');
  
  const result = JavaScriptObfuscator.obfuscate(code, {
    // 核心混淆选项
    compact: true,                              // 压缩代码
    controlFlowFlattening: true,                // 控制流扁平化(关键)
    controlFlowFlatteningThreshold: 0.75,       // 控制流打乱程度 0-1
    deadCodeInjection: true,                    // 注入死代码
    deadCodeInjectionThreshold: 0.4,            // 死代码比例
    stringArray: true,                          // 字符串数组化
    stringArrayEncoding: ['base64'],            // 字符串编码方式
    stringArrayThreshold: 0.75,                 // 字符串加密比例
    rotateStringArray: true,                    // 随机旋转字符串数组
    shuffleStringArray: true,                   // 打乱字符串数组顺序
    splitStrings: true,                         // 分割长字符串
    numbersToExpressions: true,                 // 数字转表达式
    simplify: true,                             // 简化代码
  });
  
  fs.writeFileSync(outputPath, result.getObfuscatedCode());
  console.log(`✅ 混淆完成: ${outputPath}`);
}

// 批量处理 dist 目录下的所有 JS 文件
const distDir = path.join(__dirname, '../dist');
const files = fs.readdirSync(distDir).filter(f => f.endsWith('.js'));

files.forEach(file => {
  const inputPath = path.join(distDir, file);
  const outputPath = path.join(distDir, file.replace('.js', '.obf.js'));
  obfuscateFile(inputPath, outputPath);
});

关键参数解析

参数作用推荐值注意事项
controlFlowFlattening打乱代码执行流程,增加逆向难度true会略微降低运行性能
deadCodeInjection插入无用的垃圾代码干扰分析true会增加代码体积 20-40%
stringArrayEncoding对字符串进行编码加密['base64']可选 rc4 更强但更慢
stringArrayThreshold字符串加密比例0.751.0 表示全部加密

2.2 核心逻辑后移(架构层面)

❌ 错误做法:前端硬编码

js
// renderer/index.js - 极易被破解
const LICENSE_KEY = 'ABC-123-XYZ';
if (inputLicense === LICENSE_KEY) {
  unlockFeature();
}

✅ 正确做法:后端验证

mermaid
sequenceDiagram
    participant C as Electron 客户端
    participant S as 后端 API
    participant D as 数据库
    
    C->>S: POST /api/verify-license
    Note over C,S: 发送机器指纹 + License
    S->>D: 查询 License 有效性
    D-->>S: 返回验证结果
    S-->>C: { valid: true, token: "xxx" }
    C->>C: 本地缓存 Token
    Note over C: 定期心跳验证
js
// main/license-manager.js
const axios = require('axios');
const crypto = require('crypto');

class LicenseManager {
  constructor() {
    this.apiBase = 'https://api.yourapp.com';
    this.token = null;
  }
  
  // 生成机器指纹
  getMachineFingerprint() {
    const mac = require('os').networkInterfaces().eth0?.[0]?.mac || 'unknown';
    const hostname = require('os').hostname();
    return crypto.createHash('sha256').update(`${mac}-${hostname}`).digest('hex');
  }
  
  // 验证 License
  async verifyLicense(licenseKey) {
    try {
      const response = await axios.post(`${this.apiBase}/api/verify-license`, {
        license: licenseKey,
        fingerprint: this.getMachineFingerprint(),
        timestamp: Date.now()
      });
      
      if (response.data.valid) {
        this.token = response.data.token;
        // 定时心跳验证
        setInterval(() => this.heartbeat(), 5 * 60 * 1000);
        return true;
      }
      return false;
    } catch (error) {
      console.error('License 验证失败:', error);
      return false;
    }
  }
  
  // 心跳检测
  async heartbeat() {
    if (!this.token) return;
    
    try {
      await axios.post(`${this.apiBase}/api/heartbeat`, {
        token: this.token,
        fingerprint: this.getMachineFingerprint()
      });
    } catch (error) {
      // 连续失败则退出
      this.failCount = (this.failCount || 0) + 1;
      if (this.failCount > 3) {
        app.quit();
      }
    }
  }
}

module.exports = new LicenseManager();

2.3 敏感字符串加密

AES-256-CBC 加密工具

js
// utils/crypto-helper.js
const crypto = require('crypto');

const ALGORITHM = 'aes-256-cbc';
const KEY_LENGTH = 32; // 256 bits
const IV_LENGTH = 16;  // 128 bits

class CryptoHelper {
  constructor(secretKey) {
    // 确保密钥长度为 32 字节
    this.key = Buffer.from(secretKey.padEnd(KEY_LENGTH, '0').slice(0, KEY_LENGTH));
  }
  
  // 加密
  encrypt(text) {
    const iv = crypto.randomBytes(IV_LENGTH);
    const cipher = crypto.createCipheriv(ALGORITHM, this.key, iv);
    
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    
    // IV + 密文
    return iv.toString('hex') + ':' + encrypted;
  }
  
  // 解密
  decrypt(encryptedText) {
    const parts = encryptedText.split(':');
    const iv = Buffer.from(parts[0], 'hex');
    const encrypted = parts[1];
    
    const decipher = crypto.createDecipheriv(ALGORITHM, this.key, iv);
    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    
    return decrypted;
  }
}

// 使用示例
const helper = new CryptoHelper(process.env.ENCRYPTION_KEY);

// 编译时加密敏感信息
const ENCRYPTED_API_KEY = helper.encrypt('sk_live_abc123xyz');
console.log('加密后:', ENCRYPTED_API_KEY);

// 运行时解密
const apiKey = helper.decrypt(ENCRYPTED_API_KEY);

预加密脚本

js
// scripts/encrypt-config.js
const CryptoHelper = require('../utils/crypto-helper');
const fs = require('fs');

const helper = new CryptoHelper(process.argv[2]); // 从命令行传入密钥

const config = {
  apiUrl: 'https://api.example.com',
  apiKey: 'secret-key-123',
  databaseUrl: 'mongodb://user:pass@localhost'
};

const encrypted = {};
for (const [key, value] of Object.entries(config)) {
  encrypted[key] = helper.encrypt(value);
}

fs.writeFileSync('config.encrypted.json', JSON.stringify(encrypted, null, 2));
console.log('✅ 配置加密完成');

📦 三、构建层加固(Electron 核心)

3.1 asar 打包基础

electron-builder 配置

json
// package.json
{
  "build": {
    "appId": "com.yourapp.electron",
    "productName": "YourApp",
    "asar": true,
    "asarUnpack": [
      "**/*.node"
    ]
  }
}

asar 的作用与局限

特性说明
✅ 优点将源码打包为单个归档文件,防止直接浏览文件结构
❌ 局限asar 可以被轻松解包npx asar extract app.asar output/
💡 结论必须配合加密使用,单独使用几乎无效

3.2 asar 二次加密(关键步骤)

加密脚本

js
// scripts/encrypt-asar.js
const fs = require('fs');
const crypto = require('crypto');
const path = require('path');

const ASAR_FILE = path.join(__dirname, '../dist/mac/YourApp.app/Contents/Resources/app.asar');
const ENCRYPTED_FILE = ASAR_FILE + '.enc';
const SECRET_KEY = process.env.ASAR_ENCRYPTION_KEY || 'your-secret-key-here';

function encryptAsar() {
  if (!fs.existsSync(ASAR_FILE)) {
    console.error('❌ asar 文件不存在,请先执行构建');
    process.exit(1);
  }
  
  console.log('🔐 开始加密 asar...');
  
  // 读取原始 asar
  const originalData = fs.readFileSync(ASAR_FILE);
  
  // 生成随机 IV
  const iv = crypto.randomBytes(16);
  
  // 创建加密器
  const cipher = crypto.createCipheriv('aes-256-cbc', 
    Buffer.from(SECRET_KEY.padEnd(32, '0').slice(0, 32)), 
    iv
  );
  
  // 加密
  const encrypted = Buffer.concat([
    iv,                                    // 前 16 字节存储 IV
    cipher.update(originalData),
    cipher.final()
  ]);
  
  // 写入加密后的文件
  fs.writeFileSync(ENCRYPTED_FILE, encrypted);
  
  // 删除原始 asar(重要!)
  fs.unlinkSync(ASAR_FILE);
  
  // 计算 Hash 用于完整性校验
  const hash = crypto.createHash('sha256').update(encrypted).digest('hex');
  fs.writeFileSync(ENCRYPTED_FILE + '.sha256', hash);
  
  console.log('✅ asar 加密完成');
  console.log(`📁 加密文件: ${ENCRYPTED_FILE}`);
  console.log(`🔑 SHA256: ${hash}`);
}

encryptAsar();

集成到构建流程

json
// package.json
{
  "scripts": {
    "build": "vite build && electron-builder",
    "postbuild": "node scripts/encrypt-asar.js"
  }
}

⚙️ 四、运行时解密与加载(核心技术)

4.1 主进程启动解密

js
// main/secure-loader.js
const fs = require('fs');
const crypto = require('crypto');
const path = require('path');
const { app } = require('electron');

class SecureLoader {
  constructor() {
    this.resourcesPath = app.isPackaged 
      ? path.join(process.resourcesPath)
      : path.join(__dirname, '../dist');
    
    this.encryptionKey = process.env.ASAR_ENCRYPTION_KEY || 'your-secret-key-here';
  }
  
  // 解密 asar 到内存(不落盘)
  loadEncryptedAsar() {
    const encryptedPath = path.join(this.resourcesPath, 'app.asar.enc');
    const hashPath = encryptedPath + '.sha256';
    
    // 1. 检查文件存在性
    if (!fs.existsSync(encryptedPath)) {
      console.error('❌ 加密的 asar 文件不存在');
      app.quit();
      return null;
    }
    
    // 2. 完整性校验
    if (fs.existsSync(hashPath)) {
      const expectedHash = fs.readFileSync(hashPath, 'utf-8');
      const actualHash = crypto.createHash('sha256')
        .update(fs.readFileSync(encryptedPath))
        .digest('hex');
      
      if (expectedHash !== actualHash) {
        console.error('❌ asar 文件已被篡改');
        app.quit();
        return null;
      }
    }
    
    // 3. 解密
    try {
      const encryptedData = fs.readFileSync(encryptedPath);
      const iv = encryptedData.slice(0, 16);
      const encrypted = encryptedData.slice(16);
      
      const decipher = crypto.createDecipheriv('aes-256-cbc',
        Buffer.from(this.encryptionKey.padEnd(32, '0').slice(0, 32)),
        iv
      );
      
      const decrypted = Buffer.concat([
        decipher.update(encrypted),
        decipher.final()
      ]);
      
      console.log('✅ asar 解密成功');
      return decrypted;
      
    } catch (error) {
      console.error('❌ 解密失败:', error.message);
      app.quit();
      return null;
    }
  }
  
  // 从内存加载模块(高级用法)
  loadModuleFromMemory(moduleName, decryptedBuffer) {
    const vm = require('vm');
    const Module = require('module');
    
    // 创建沙箱上下文
    const sandbox = {
      module: { exports: {} },
      exports: {},
      require: require,
      __filename: moduleName,
      __dirname: path.dirname(moduleName)
    };
    
    // 执行代码
    const code = decryptedBuffer.toString('utf-8');
    vm.runInNewContext(code, sandbox);
    
    return sandbox.module.exports;
  }
}

module.exports = new SecureLoader();

4.2 在主进程中调用

js
// main/main.js
const { app, BrowserWindow } = require('electron');
const SecureLoader = require('./secure-loader');

let mainWindow;

function createWindow() {
  // 先解密 asar
  const decryptedAsar = SecureLoader.loadEncryptedAsar();
  
  if (!decryptedAsar) {
    return; // 解密失败已退出
  }
  
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js')
    }
  });
  
  // 加载页面
  mainWindow.loadURL('app://./index.html');
}

app.whenReady().then(createWindow);

🛡️ 五、运行时安全防护

5.1 禁用开发者工具

js
// main/security.js
function disableDevTools(window) {
  // 禁止打开 DevTools
  window.webContents.on('devtools-opened', () => {
    console.warn('⚠️ 检测到 DevTools 被打开,立即关闭');
    window.webContents.closeDevTools();
  });
  
  // 禁用快捷键
  window.webContents.on('before-input-event', (event, input) => {
    if (
      (input.control || input.meta) && 
      input.key.toLowerCase() === 'i'
    ) {
      event.preventDefault();
    }
    if (
      (input.control || input.meta) && 
      input.key.toLowerCase() === 'u'
    ) {
      event.preventDefault();
    }
  });
}

5.2 防调试检测

js
// main/anti-debug.js
class AntiDebug {
  constructor() {
    this.checkInterval = null;
    this.suspiciousCount = 0;
  }
  
  start() {
    // 方法 1: debugger 语句时间差检测
    this.checkInterval = setInterval(() => {
      const startTime = performance.now();
      debugger; // 如果被调试,这里会暂停
      const endTime = performance.now();
      
      // 如果暂停超过 100ms,认为正在被调试
      if (endTime - startTime > 100) {
        this.suspiciousCount++;
        console.warn(`⚠️ 检测到调试行为 (${this.suspiciousCount}/3)`);
        
        if (this.suspiciousCount >= 3) {
          console.error('🚫 多次检测到调试,应用将退出');
          setTimeout(() => process.exit(1), 1000);
        }
      } else {
        this.suspiciousCount = Math.max(0, this.suspiciousCount - 1);
      }
    }, 2000);
    
    // 方法 2: 检测常见调试工具
    this.detectDebuggerTools();
  }
  
  detectDebuggerTools() {
    // 检测 Chrome DevTools Protocol
    const net = require('net');
    const server = net.createServer();
    
    server.on('error', (err) => {
      if (err.code === 'EADDRINUSE') {
        console.error('🚫 检测到端口占用,可能正在被调试');
        process.exit(1);
      }
    });
    
    server.listen(9229, () => {
      server.close();
    });
  }
  
  stop() {
    if (this.checkInterval) {
      clearInterval(this.checkInterval);
    }
  }
}

module.exports = new AntiDebug();

5.3 完整性校验体系

js
// main/integrity-check.js
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const { app } = require('electron');

class IntegrityChecker {
  constructor() {
    this.expectedHashes = {
      'app.asar.enc': '预设的SHA256值',
      'main.js': '预设的SHA256值',
      'preload.js': '预设的SHA256值'
    };
  }
  
  // 计算文件 Hash
  calculateHash(filePath) {
    const data = fs.readFileSync(filePath);
    return crypto.createHash('sha256').update(data).digest('hex');
  }
  
  // 校验所有关键文件
  verifyAll() {
    const resourcesPath = app.isPackaged
      ? process.resourcesPath
      : path.join(__dirname, '../dist');
    
    for (const [file, expectedHash] of Object.entries(this.expectedHashes)) {
      const filePath = path.join(resourcesPath, file);
      
      if (!fs.existsSync(filePath)) {
        console.error(`❌ 关键文件缺失: ${file}`);
        return false;
      }
      
      const actualHash = this.calculateHash(filePath);
      if (actualHash !== expectedHash) {
        console.error(`❌ 文件被篡改: ${file}`);
        console.error(`   期望: ${expectedHash}`);
        console.error(`   实际: ${actualHash}`);
        return false;
      }
    }
    
    console.log('✅ 完整性校验通过');
    return true;
  }
  
  // 定期校验(防止运行时替换)
  startPeriodicCheck(intervalMs = 5 * 60 * 1000) {
    setInterval(() => {
      if (!this.verifyAll()) {
        console.error('🚫 周期性校验失败,应用将退出');
        setTimeout(() => app.quit(), 1000);
      }
    }, intervalMs);
  }
}

module.exports = new IntegrityChecker();

📡 六、分发层安全

6.1 代码签名(必须)

Windows 代码签名

json
// package.json
{
  "build": {
    "win": {
      "sign": "./scripts/sign-windows.js",
      "certificateFile": "cert.pfx",
      "certificatePassword": "your-password"
    }
  }
}

macOS 代码签名

json
{
  "build": {
    "mac": {
      "identity": "Developer ID Application: Your Company (XXXXX)",
      "hardenedRuntime": true,
      "gatekeeperAssess": false,
      "entitlements": "build/entitlements.mac.plist",
      "entitlementsInherit": "build/entitlements.mac.inherit.plist"
    }
  }
}
xml
<!-- build/entitlements.mac.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>com.apple.security.cs.allow-jit</key>
  <true/>
  <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
  <true/>
  <key>com.apple.security.cs.disable-library-validation</key>
  <true/>
</dict>
</plist>

6.2 安全自动更新

electron-updater 配置

js
// main/updater.js
const { autoUpdater } = require('electron-updater');
const { dialog } = require('electron');

class SecureUpdater {
  constructor() {
    autoUpdater.autoDownload = false;
    autoUpdater.autoInstallOnAppQuit = true;
    
    // 设置更新服务器(必须 HTTPS)
    autoUpdater.setFeedURL({
      provider: 'generic',
      url: 'https://updates.yourapp.com',
      channel: 'latest'
    });
  }
  
  async checkForUpdates() {
    try {
      const info = await autoUpdater.checkForUpdates();
      
      if (info.updateInfo) {
        console.log(`发现新版本: ${info.updateInfo.version}`);
        
        // 校验更新包 Hash
        const expectedSha512 = info.updateInfo.files[0].sha512;
        console.log(`预期 Hash: ${expectedSha512}`);
        
        // 下载更新
        autoUpdater.downloadUpdate();
      }
    } catch (error) {
      console.error('更新检查失败:', error);
    }
  }
  
  init() {
    autoUpdater.on('update-downloaded', (info) => {
      dialog.showMessageBox({
        type: 'info',
        title: '更新就绪',
        message: `新版本 ${info.version} 已下载完成`,
        detail: '应用将在重启后自动安装',
        buttons: ['立即重启', '稍后']
      }).then(({ response }) => {
        if (response === 0) {
          autoUpdater.quitAndInstall();
        }
      });
    });
    
    autoUpdater.on('error', (error) => {
      console.error('更新失败:', error);
    });
  }
}

module.exports = new SecureUpdater();

🏢 七、企业级终极方案

7.1 前后端分离架构

mermaid
graph TB
    subgraph 客户端
        A[Electron Shell] --> B[混淆的前端 UI]
        B --> C[Preload 脚本]
    end
    
    subgraph 服务端
        D[API Gateway] --> E[认证服务]
        D --> F[业务逻辑服务]
        D --> G[数据存储服务]
        E --> H[Redis 会话管理]
        F --> I[MySQL/PostgreSQL]
    end
    
    C -->|HTTPS + JWT| D
    D -->|加密响应| C
    
    style A fill:#e1f5ff
    style B fill:#fff4e1
    style D fill:#e8f5e9

7.2 方案对比

方案安全性实现难度维护成本适用场景
纯客户端⭐⭐个人项目、演示版
混淆 + 加密⭐⭐⭐小型商业软件
完整加固⭐⭐⭐⭐中型商业软件
前后端分离⭐⭐⭐⭐⭐很高很高大型企业应用

💣 八、常见错误与避坑指南

8.1 典型错误清单

错误做法风险等级后果正确做法
❌ 只用 asar 打包🔴 极高可一键解包asar + 二次加密
❌ 只混淆不加密🟠 高工具可还原混淆 + 字符串加密
❌ 密钥硬编码🔴 极高等同于明文环境变量 + 动态获取
❌ 解密后落盘🟠 高可被内存 dump内存中解密执行
❌ 忽略完整性校验🟡 中文件可被替换SHA256 定期校验
❌ 不禁用 DevTools🟡 中方便调试分析禁用 + 防调试检测

8.2 安全检查清单

markdown
## 发布前安全检查

- [ ] JS 代码已混淆(javascript-obfuscator)
- [ ] 敏感字符串已加密(AES-256)
- [ ] asar 已二次加密
- [ ] 加密密钥未硬编码
- [ ] 运行时解密不落盘
- [ ] DevTools 已禁用
- [ ] 防调试机制已启用
- [ ] 文件完整性校验已配置
- [ ] 代码签名已完成
- [ ] 更新服务器使用 HTTPS
- [ ] 核心逻辑已移至后端(如适用)

🚀 九、推荐组合方案(生产可用)

9.1 标准加固方案

✅ javascript-obfuscator     → 代码混淆
✅ AES-256-CBC               → 字符串加密
✅ asar 打包                  → 基础归档
✅ asar 二次加密              → 增强保护
✅ 内存解密加载               → 避免落盘
✅ SHA256 完整性校验          → 防篡改
✅ 防调试 + 禁用 DevTools     → 增加逆向难度
✅ 代码签名                   → 防分发篡改
✅ 核心逻辑后移至 API         → 终极保护

9.2 实施优先级

优先级措施投入产出比
P0asar + 混淆⭐⭐⭐⭐⭐
P0核心逻辑后端化⭐⭐⭐⭐⭐
P1asar 二次加密⭐⭐⭐⭐
P1字符串加密⭐⭐⭐⭐
P2防调试检测⭐⭐⭐
P2代码签名⭐⭐⭐
P3完整性定期校验⭐⭐

📝 十、面试标准回答模板

Q1: Electron 应用如何防止源码泄露?

回答要点:

"Electron 由于基于 Chromium 和 Node.js,源码天然是明文的。我们采用多层防护策略:

  1. 源码层:使用 javascript-obfuscator 进行代码混淆,包括控制流扁平化、字符串数组化、死代码注入等;
  2. 构建层:除了默认的 asar 打包外,还对 asar 进行 AES-256 二次加密;
  3. 运行时:在内存中解密 asar,避免落盘;同时禁用 DevTools 并加入防调试检测;
  4. 架构层:最核心的业务逻辑放在后端 API,客户端只做 UI 展示。

这样即使客户端被破解,也无法获取核心算法和数据。"


Q2: asar 打包是否安全?

回答要点:

"单独使用 asar 非常不安全。因为:

  • asar 只是简单的归档格式,可以用 npx asar extract 一键解包
  • 没有任何加密或混淆

正确做法是:

  1. asar 打包后进行 AES 加密
  2. 运行时在内存中解密
  3. 配合代码混淆使用

这样才能真正提高破解成本。"


Q3: 如何保护 API 密钥等敏感信息?

回答要点:

"有三种方案,按安全性递增:

  1. 编译时加密:在构建阶段用 AES 加密密钥,运行时解密(但仍可在内存中找到)
  2. 环境变量:通过 CI/CD 注入,不写入代码库
  3. 后端代理(推荐):客户端不存储任何密钥,所有敏感请求通过自己的后端转发

对于商业产品,强烈推荐第三种方案,从根本上杜绝客户端泄露风险。"


🧠 十一、记忆口诀

Electron 安全要记牢,四层防护不能少:
混淆加密第一步,asar 打包加密封。
内存解密不落盘,防调校验双保险。
代码签名防篡改,核心逻辑放后端。
绝对安全做不到,提高成本是王道!

📚 十二、相关资源

资源类型链接说明
官方文档electronjs.org/docs/tutorial/securityElectron 安全最佳实践
混淆工具javascript-obfuscatorGitHub 12k+ Stars
代码签名Microsoft SignToolWindows 代码签名工具
更新框架electron-updater自动更新解决方案
安全审计Electron Security Checklist官方安全检查清单

最近更新